package com.fiume.demo;

import com.alibaba.fastjson.JSON;
import com.fiume.pojo.User;
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.Map;

/**
 * <p>
 * Description:
 * </p>
 *
 * @author fiume
 * @version v1.0.0
 * @create 2021-01-15 21:00
 * @see com.fiume.demo
 */
public class Day03Query {
    private RestHighLevelClient client;

    //查询所有人
    //GET /索引库名/_search
    //{
    //    "query":{
    //        "查询类型":{
    //            "查询条件":"查询条件值"
    //        }
    //    }
    //}
    @Test
    public void matchAllTest() throws IOException {
        //2.创建资源加载器,构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //3.添加查询方法(查询所有)
        sourceBuilder.query(QueryBuilders.matchAllQuery());
        //3.处理请求
        doAndResponse(sourceBuilder);
    }

    //2.词条查询-matchQuery

    //# 查看分词效果，得到“学”和“唱歌”
    //GET /_analyze
    //{
    //  "text": "学唱歌"
    //}

    //# match查询, “学唱歌”分成“学”和“唱歌”两个词，包含任意一个词条都算匹配成功
    //GET /user/_search
    //{
    //  "query": {
    //    "match": {
    //      "note": "学唱歌"
    //    }
    //  }
    //}
    @Test
    public void matchQueryTest() throws IOException {

        //2.创建资源加载器,构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //3.添加查询方法(查询单个)
        sourceBuilder.query(QueryBuilders.matchQuery("note", "学表演"));
        //4.发起请求
        doAndResponse(sourceBuilder);
    }

    //3.分词匹配查询-termQuery
    @Test
    public void termQueryTest() throws IOException {
        //2.创建资源加载器,构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //3.添加查询方法(分词匹配查询)
        sourceBuilder.query(QueryBuilders.termQuery("name", "Rose"));
        //3.发起请求
        doAndResponse(sourceBuilder);
    }

    //4.模糊查询-fuzzy
    //GET /user/_search
    //{
    //  "query": {
    //    "match": {
    //      "note": {
    //        "query": "表演",
    //        "fuzziness": 1
    //      }
    //    }
    //  }
    //}
    @Test
    public void fuzzyQueryTest() throws IOException {
        //1.2创建资源加载器,构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //3.添加查询方法(模糊查询)
        sourceBuilder.query(QueryBuilders.matchQuery("note", "表演").fuzziness(1));
        //3.发起请求
        doAndResponse(sourceBuilder);
    }

    //5.范围查询-range
    //GET /user/_search
    //{
    //  "query": {
    //    "range": {
    //      "age": {
    //        "gte": 10,
    //        "lte": 25
    //      }
    //    }
    //  }
    //}
    @Test
    public void rangeQueryTest() throws IOException {
        //1.创建资源加载器,构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //3.添加查询方法(范围查询)
        sourceBuilder.query(QueryBuilders.rangeQuery("age")
                .gte(10).lte(25));
        //3.发起请求
        doAndResponse(sourceBuilder);
    }

    //6.bool查询
    //GET /user/_search
    //{
    //  "query": {
    //    "bool": {
    //      "must": [
    //        {
    //          "range": {
    //            "age": {
    //              "gte": 10,
    //              "lte": 20
    //            }
    //          }
    //        },
    //        {
    //          "match": {
    //            "note": {
    //              "query": "学表演",
    //              "fuzziness": 1
    //            }
    //          }
    //        }
    //      ]
    //    }
    //  }
    //}
    @Test
    public void boolQueryTest() {
        //1.创建资源加载器,构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //3.添加查询方法(范围查询)
        sourceBuilder.query(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.rangeQuery("age").gte(10).lte(20))
                        .must(QueryBuilders.matchQuery("note", "学表演").fuzziness(1))
                        .filter(QueryBuilders.termQuery("gender", 0)));
        //3.发起请求
        try {
            doAndResponse(sourceBuilder);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //7.排序
    //GET /user/_search
    //{
    //  "query": {
    //    "bool": {
    //      "must": [
    //        {
    //          "range": {
    //            "age": {
    //              "gte": 10,
    //              "lte": 20
    //            }
    //          }
    //        },
    //        {
    //          "match": {
    //            "note": {
    //              "query": "学表演",
    //              "fuzziness": 1
    //            }
    //          }
    //        }
    //      ]
    //    }
    //  },
    //  "sort": [
    //    {
    //      "age": {
    //        "order": "desc"
    //      }
    //    }
    //  ]
    //}

    @Test
    public void sortTest() {
        //1.创建资源加载器,构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //3.添加查询方法(范围查询)
        sourceBuilder.query(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.rangeQuery("age").gte(10).lte(20))
                        .must(QueryBuilders.matchQuery("note", "学表演").fuzziness(1)))
                .sort("age", SortOrder.ASC);
        //3.发起请求
        try {
            doAndResponse(sourceBuilder);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    //8.分页查询-from
    //GET /user/_search
    //{
    //  "query": {
    //    "match_all": {}
    //  },
    //  "sort": [
    //    {
    //      "age": {
    //        "order": "desc"
    //      }
    //    }
    //  ],
    //  "from": 0 , "size": 5
    //}

    @Test
    public void pageTest() {
        //1.创建资源加载器,构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //3.添加查询方法(范围查询)
        sourceBuilder.query(
                QueryBuilders.matchAllQuery())
                .sort("age", SortOrder.ASC)
                .from(0).size(5);
        //3.发起请求
        try {
            doAndResponse(sourceBuilder);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //9.高亮查询-highlight
    //GET /user/_search
    //{
    //  "query": {
    //    "match": {
    //      "note": "学跳舞"
    //    }
    //  },
    //  "sort": [
    //    {
    //      "age": {
    //        "order": "desc"
    //      }
    //    }
    //  ],
    //  "from": 0 , "size": 5,
    //  "highlight": {
    //    "pre_tags": "<em>",
    //    "post_tags": "</em>",
    //    "fields": {
    //      "note": {}
    //    }
    //  }
    //}
    @Test
    public void highLightQueryTest() throws IOException {

        //1.创建资源加载器,构建查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //2.添加查询方法(条件查询)
        sourceBuilder.query(QueryBuilders.matchQuery("note", "学唱歌"))
                .sort("age", SortOrder.DESC)
                .from(0).size(5)
                .highlighter(
                        new HighlightBuilder()
                                .field("note")
                                .preTags("<em>")
                                .postTags("</em>")
                );
        //3.发起请求
        doAndResponse(sourceBuilder);
    }


    //10.聚合查询-aggregation

    private void doAndResponse(SearchSourceBuilder sourceBuilder) throws IOException {
        //1.创建request对象,指定库   GET /user/_search
        SearchRequest searchRequest = new SearchRequest("user");
        //2.拼装
        searchRequest.source(sourceBuilder);
        //3.发起请求
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        //4.解析结果
        SearchHits responseHits = searchResponse.getHits();
        //4.1 获取总条数
        long total = responseHits.getTotalHits().value;
        System.out.println("total = " + total);
        //4.2 获取hits内的内容
        SearchHit[] hits = responseHits.getHits();
        //4.2.1 将之转化为对象
        for (SearchHit hit : hits) {
            String json = hit.getSourceAsString();
            User user = JSON.parseObject(json, User.class);
            //4.3 获取高亮结果
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            //4.3.2 判断结果是否存在
            if (highlightFields != null && !highlightFields.isEmpty()){
                HighlightField note = highlightFields.get("note");
                Text[] fragments = note.getFragments();
                String s = fragments[0].toString();
                user.setNote(s);
                /*// 4.4.1.根据字段名，获取高亮结果
                HighlightField field = highlightFields.get("note");
                // 4.4.2.获取高亮片段（fragments
                Text[] fragments = field.getFragments();
                // 4.4.3.拼接高亮片段
                String hNote = StringUtils.join(fragments);
                // 4.4.4.覆盖非高亮结果
                user.setNote(hNote);*/

            }
            System.out.println("user = " + user);
        }
    }

    @Before
    public void setUp() throws Exception {
        client = new RestHighLevelClient(
                RestClient.builder(
                        HttpHost.create("http://192.168.203.130:9200")));
    }

    @After
    public void tearDown() throws Exception {
        client.close();
    }

}
